Enumerate the tools available to the agent.
Backs two entry points: the dcode tools list CLI command (_run_tools_list)
and the interactive /tools slash command (app._handle_tools_command).
The tool set is read from the real tool objects the agent binds rather than a hand-maintained catalog, so names and descriptions never drift from what the model actually sees. Built-in tools are collected by compiling the agent with a throwaway offline chat model (no credentials, no network) and reading the bound tool node; MCP tools are discovered via the same path the app and server use.
The collection functions here lazily import the heavy agent stack (agent
compilation, MCP discovery) inside their bodies. Only the fake-model base is
imported at module top, so importing this module is cheap relative to the agent
stack — and this module is itself imported lazily by both entry points
(_run_tools_list and _handle_tools_command), never on the startup hot path.
Mirror of the SDK's FsToolName literal members.
Hardcoded here rather than derived from deepagents.FsToolName because
deepagents must not be imported on the arg-parsing hot path (see AGENTS.md
"Startup performance"); this module is dependency-free and safe for main.py to
import. Consumers (main._parse_allow_fs_tools_flag,
tool_catalog.collect_built_in_tools) alias this set, and get_args(FsToolName)
drift guards in test_main_args and test_tool_catalog pin it so a new or
renamed SDK filesystem tool fails a test instead of silently diverging.
Load states a configured MCP server can end up in.
ok means the server loaded successfully and has an authoritative tool list.
unauthenticated means the server requires OAuth login before tools can load.
error means the server failed to load after a connection or configuration
failure.
disabled is set when the user has turned the server off via the TUI
(/mcp -> F2). No connection is attempted and no tools are loaded, but
the entry is still surfaced in the viewer so the user can re-enable it.
awaiting_reconnect is a transient UI-only state used after OAuth login
has succeeded but before the LangGraph server has restarted and loaded
the newly available MCP tools.
Stable source token identifying where a tool group comes from.
Emitted verbatim in the --json output, so it is a public contract; keep it a
Literal of stable tokens (not a bare str), following the same convention as
mcp_tools.MCPServerStatus.
Display label for the group of tools bundled with deepagents-code.
Return the (status_label, detail) display pair for an unavailable server.
Shared by the CLI (client.commands.tools._print_unavailable_servers) and
TUI (app._render_tool_catalog) renderers so both describe a server the same
way. A disabled server shows its reconnect guidance if present, else the
generic "disabled by user", with no separate detail; other statuses show the
status token plus discovery's reason string when present.
Enumerate the built-in tools the agent binds by default.
Compiles the agent with an offline placeholder model and reads the bound
tool node. Memory and skills are disabled because they contribute no tools
(they only augment the system prompt). The selected assistant id is still
forwarded so agent-specific subagents are loaded from the same directory the
normal launch path uses. The custom CLI tools are included the same way
server_graph._build_tools adds them, so web_search appears only when
Tavily is configured.
Read tools from a local compiled agent when its graph is inspectable.
LangGraph does not expose a public tool-enumeration API, so this reaches
through the compiled graph's conventional nodes["tools"].bound shape.
Returning None distinguishes an uninspectable graph (a remote agent, or a
local graph whose internals no longer match that convention) from a local
graph that validly binds zero tools ([]).
Discover MCP servers, split into tool groups and unavailable servers.
Best-effort: if discovery itself raises (no config, offline, load error),
the technical detail is logged and a generic mcp_error message is
returned so dcode tools list still renders the built-in tools while
telling the user discovery failed. Servers that loaded but expose no tools
are reported as UnavailableServers (errored, needing login, or disabled)
rather than silently dropped — surfacing exactly what a user running this
command to debug a missing tool needs to see.
Split loaded MCP server metadata into tool groups and unavailable servers.
Pure function shared by the CLI discovery path (collect_mcp_catalog) and
the interactive /tools command, which passes the app's already-loaded
MCPServerInfo list rather than re-discovering (Textual's running event
loop forbids the asyncio.run discovery path).
Servers that loaded but expose no tools are reported as UnavailableServers
(errored, needing login, or disabled) rather than silently dropped —
surfacing exactly what a user debugging a missing tool needs to see.
Assemble a ToolCatalog from pre-collected built-in tools and live MCP info.
The interactive /tools command entry point: it avoids the asyncio.run
MCP discovery reached via collect_catalog (the asyncio.run call itself
lives in collect_mcp_catalog), which cannot run inside Textual's running
event loop, by reusing the MCP metadata the app already loaded. mcp_error
is always None here because discovery is not attempted — any load failures
are already reflected per-server in server_info as non-ok MCPServerInfo
entries, which split_mcp_server_info surfaces as UnavailableServers.
Collect everything dcode tools list renders.
Metadata for a configured MCP server and its tools.
A single tool's display metadata.
A named group of tools sharing a source.
An MCP server that was discovered but currently exposes no tools.
Everything dcode tools list needs to render, in display order.